/*
 * timermgt.cpp
 *
 *  Created on: 2011-3-19
 *      Author: chenl
 */
#include "timer/timermgt.h"
#include "common/common_type.h"
#include "datetime/datetime.h"
#include "common/common_util.h"
#include <utility>

CTimerMgt::TimerID CTimerMgt::SetTimer(int enmTimerType, int nOwnerID,
		int64_t nCycleTime, bool bIsTimerCycle, int nAtt0, int nAtt1)
{
	// set timer
	Timer timer;
	timer.enmTimerType = enmTimerType;
	timer.nOwnerID = nOwnerID;
	timer.nCycleTime = nCycleTime;
	timer.bIsTimerCycle = bIsTimerCycle;
	timer.nStartTime = CDateTime::CurrentDateTime().uSeconds();
	timer.nEndTime = timer.nStartTime + timer.nCycleTime;
	timer.nAttData0 = nAtt0;
	timer.nAttData1 = nAtt1;
	timer.nFireCount = 0;

	bool bInsertSuccess = false;

	do
	{
		// generate timerID
		++nCurrTimerIDMapped_; // nCurrTimerIDMapped_ started from 0
		if (0 == nCurrTimerIDMapped_)
			++nCurrTimerIDMapped_; // denote that ZERO is NOT an invalid timer ID
		// insert timer to timerMap_ with TimerID for key. if TimerID exists, it is increased by 1 and try again
		bInsertSuccess = (timerMap_.insert(std::pair<TimerID, Timer>(
				nCurrTimerIDMapped_, timer))).second; // warning: assuming map::insert inserts a copy
	} while (!bInsertSuccess);
	// insert ID to timerIDList_ with Timer.nEndTime for key for auto sorting (less in front)
	timerIDList_.insert(std::pair<int64_t, TimerID>(timer.nEndTime,
			nCurrTimerIDMapped_)); // warning: assuming map::insert inserts a copy

	return nCurrTimerIDMapped_;
}

int32_t CTimerMgt::GetTimer(const TimerID& timerID, Timer& timer)
{
	// find timer in timerMap_
	TimerMap::iterator itrMap = timerMap_.find(timerID);
	if (timerMap_.end() == itrMap)
	{
		return S_FALSE; // FIXME: what about timerIDList_? how to verify that the timer id is not in it?
	}
	timer = itrMap->second;
	return S_OK;
}

int32_t CTimerMgt::TimerFired(const TimerID& timerID)
{
	// find timer in timerMap_
	TimerMap::iterator itrMap = timerMap_.find(timerID);
	if (timerMap_.end() == itrMap)
	{
		assert(!"FIXME: what about timerIDList_? how to verify that the timer id is not in it?");
		return S_FALSE; // FIXME: what about timerIDList_? how to verify that the timer id is not in it?
	}

	if (itrMap->second.bIsTimerCycle)
	{
		TimerIDList::iterator itrList = _FindTimerIDByEndTime(itrMap->second.nEndTime, timerID);
		// reinsert
		if (timerIDList_.end() == itrList)
		{
			timerMap_.erase(timerID);
			return S_FALSE;
		}
		itrMap->second.nEndTime += itrMap->second.nCycleTime;
		timerIDList_.erase(itrList);
		timerIDList_.insert(std::pair<int64_t, TimerID>(itrMap->second.nEndTime,
				timerID));
	}
	else // delete the timer
	{
		return DestoryTimer(timerID);
	}
	return S_OK;
}

int32_t CTimerMgt::DestoryTimer(const TimerID& timerID)
{
	// find timer in timerMap_
	TimerMap::iterator itrMap = timerMap_.find(timerID);
	if (timerMap_.end() == itrMap)
	{
		return S_FALSE; // FIXME: what about timerIDList_? how to verify that the timer id is not in it?
	}
	int64_t nEndTime = itrMap->second.nEndTime;
	timerMap_.erase(itrMap);
	// find timer in timerIDList_
	TimerIDList::iterator itrList = _FindTimerIDByEndTime(nEndTime, timerID);

	if (timerIDList_.end() == itrList)
	{
		return S_FALSE;
	}
	timerIDList_.erase(itrList);
	return S_OK;
}

CTimerMgt::TimerIDList::iterator CTimerMgt::_FindTimerIDByEndTime(
		int64_t nEndTime, const TimerID& timerID)
{
	std::pair<TimerIDList::iterator, TimerIDList::iterator> itrRange = timerIDList_.equal_range(
			nEndTime);
	if (timerIDList_.end() == itrRange.first)
		return timerIDList_.end(); // not found
	if (likely(itrRange.first == itrRange.second))	// only one value matches
	{
		return itrRange.first;
	}

	TimerIDList::iterator itr = itrRange.first;
	while (itrRange.second != itr)	// multiple values match
	{
		if (timerID == itr->second)
		{
			return itr;
		}
		++itr;
	}
	if (timerID == itr->second)
	{
		return itr;
	}
	return timerIDList_.end();
}
